"""This module provides mydouyn"""

import asyncio
import json
import logging
import os
import platform
import random
import subprocess
import sys
import threading
import time
import traceback

import aiofiles
import pyperclip
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
from playwright.async_api import Playwright, async_playwright
from playwright.sync_api import Page, sync_playwright

######################global########################
LOG_FORMAT = (
    "[%(asctime)s][%(levelname)s][%(filename)s:%(funcName)s:%(lineno)d] %(message)s"
)
DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
TOTAL_WORK_TIME = 180
TOTAL_COUNT = 0
one_work_time = 30
# STEPS = 10
STEPS = 10
TOTAL_WORK_TIME_COUNT = 0


########################################################################
class CZTOUYU:
    """
    This class represents a GetupHabit.

    Parameters:
    - save_picture_path (str): The path to save pictures.
    - default_picture_path (str): The default path for pictures.
    """

    def __init__(
        self,
        cookies_path: str,
        login_url: str,
        zhibo_url: str,
        watch_room_url: str,
        mp4_input_directory: str,
        only_msg,
    ):
        self.cookies_path = cookies_path
        self.login_url = login_url
        self.zhibo_url = zhibo_url
        self.watch_room_url = watch_room_url
        # playwright 部分
        self.browser = None
        self.input_directory = mp4_input_directory
        self.only_msg = only_msg
        print("create CZTOUYU")

    def __del__(self):
        print("CZTOUYU is being destroyed")

    async def auto_start_zhibo(
        self, picture_path: str, habit_name: str, habit_detail: str
    ):
        """
        定时直播 不是24小时 推送 很容易断流 被扣分
        """
        async with async_playwright() as playwright:
            display_headless = False
            if platform.system() == "Linux":
                display_headless = True
            if sys == "Linux":
                self.browser = await playwright.chromium.launch(
                    headless=display_headless
                )
            else:
                self.browser = await playwright.chromium.launch(
                    channel="chrome", headless=display_headless
                )

            login_page = await self.login_or_restore_cookies()
            try:
                await self.helper_start_zhibo(
                    login_page, picture_path, habit_name, habit_detail
                )
                if self.browser.is_connected:
                    await self.browser.close()
            except Exception as mye:
                print(mye)

    async def auto_stop_zhibo(self):
        """停止直播"""
        async with async_playwright() as playwright:
            display_headless = False
            if platform.system() == "Linux":
                display_headless = True
            if sys == "Linux":
                self.browser = await playwright.chromium.launch(
                    headless=display_headless
                )
            else:
                self.browser = await playwright.chromium.launch(
                    channel="chrome", headless=display_headless
                )

            login_page = await self.login_or_restore_cookies()
            await self.helper_stop_zhibo(login_page)
            if self.browser.is_connected:
                await self.browser.close()

    async def login_or_restore_cookies(self) -> Page:
        """
        登录
        """
        context = await self.browser.new_context()
        await context.clear_cookies()
        page = await context.new_page()
        await page.goto(self.login_url)

        if os.path.exists(self.cookies_path):
            print("load cookies")
            # 从文件中加载 cookies
            async with aiofiles.open(self.cookies_path, "r", encoding="utf-8") as f:
                content = await f.read()
                cookies = json.loads(content)
            await context.add_cookies(cookies)
            await page.wait_for_timeout(3 * 1000)
        else:
            # 扫名二维码登录 需要人工处理
            await page.wait_for_timeout(30 * 1000)
            cookies = await context.cookies()
            async with aiofiles.open(self.cookies_path, "w", encoding="utf-8") as f:
                await f.write(json.dumps(cookies))
        print("login_or_restore_cookies")
        return page

    async def helper_start_zhibo(
        self, page: Page, picture_path: str, habit_name: str, habit_detail: str
    ):
        """
        解析直播推流地址：防止自动黑屏 断流后 扣费 定时直播2个小时。
        """

        await page.goto(self.zhibo_url)
        await page.wait_for_timeout(8 * 1000)
        print(f"open  {self.zhibo_url}")
        await page.mouse.down()
        print(picture_path, habit_name, habit_detail)

        # Text match
        # https://sqa.stackexchange.com/questions/29079/how-to-access-a-hyper-link-using-xpath
        # await page.locator("xpath=//span[contains(text(),'开始直播')]").click()
        await page.locator("css=.start--1NvkXEZ").click()
        await page.wait_for_timeout(10 * 1000)
        print("1 点击开始直播完成")

        await page.get_by_text("确定").click()
        await page.wait_for_timeout(5 * 1000)
        print("2 点击确定直播完成")
        # 从直播房价调回去
        await page.goto(self.zhibo_url)
        await page.wait_for_timeout(10 * 1000)
        print(f"3 开始直播调整到播放页面，现在跳回去{self.zhibo_url}")

        dropdown = page.locator("css=.svgIcon--2ypAR1M.svg--2uID9Py").locator("nth=0")
        await dropdown.hover()
        print("4 开始获取推流地址")
        await page.wait_for_timeout(1 * 1000)
        await dropdown.click()
        await page.wait_for_timeout(2 * 1000)
        rtpm_url = pyperclip.paste()
        await page.wait_for_timeout(1 * 1000)
        print(f"5 获取推流地址完成 {rtpm_url}")
        # rtmp://sendtc3.douyu.com/live
        dropdown1 = page.locator("css=.svgIcon--2ypAR1M.svg--2uID9Py").locator("nth=1")
        await dropdown1.hover()
        await page.wait_for_timeout(2 * 1000)
        await dropdown1.click()
        # 等待2秒获取黏贴内容
        await page.wait_for_timeout(2 * 1000)
        rtpm_code = pyperclip.paste()
        await page.wait_for_timeout(2 * 1000)
        print(f"6 获取直播码 {rtpm_code}")

        rtmp_stream = rtpm_url + "/" + rtpm_code
        print(f"7 完整推流地址：{rtmp_stream}")

        await page.wait_for_timeout(5 * 1000)
        await self.browser.close()
        print(f"8 关闭浏览器")

        # 开始推流
        await rtmp_timeout_task(self.input_directory, rtmp_stream)
        print(f"9 直播结束：{self.watch_room_url}")

        await self.auto_stop_zhibo()
        print(f"10 关闭直播：{self.watch_room_url}")

    async def helper_stop_zhibo(self, page: Page):
        """
        自动停直播
        """
        try:
            await page.goto(self.zhibo_url)
            await page.wait_for_timeout(6 * 1000)
            await page.mouse.down()
            await page.wait_for_timeout(1 * 1000)
            print("关闭直播")
            await page.get_by_text("关闭直播").click()
            await page.wait_for_timeout(10 * 1000)
            await page.get_by_text("直接下播").click()
            await page.wait_for_timeout(10 * 1000)
        except Exception as mye:
            print(mye)


def get_task_msg():
    """task"""
    global TOTAL_COUNT
    global TOTAL_WORK_TIME_COUNT
    get_work_time = STEPS * TOTAL_COUNT
    TOTAL_WORK_TIME_COUNT += STEPS
    print(get_work_time)
    get_off_work_time = TOTAL_WORK_TIME - get_work_time
    get_rest_time = one_work_time - get_work_time
    print(get_rest_time)

    if get_off_work_time <= 0 or get_rest_time <= 0:
        get_off_work_time = 0
        get_rest_time = 0
        TOTAL_COUNT = 0


async def interface_auo_start_douyu_zhibo(input_directory, only_msg):
    """
    对外调用接口
    """
    login_url = "https://www.douyu.com/"
    zhibo_url = "https://www.douyu.com/creator/main/live"
    watch_room_url = "https://www.douyu.com/11975253"
    if platform.system() == "Windows":
        cookies_path = r"D:\mp4\etc\douyu_small.json"
    elif platform.system() == "Darwin":
        cookies_path = r"/Users/wangchuanyi/mp4/etc/douyu_small.json"
    else:
        cookies_path = r"/root/bin/zhibodouyu.json"

    file_path = ""
    habit_name = ""
    habit_detail = ""
    autoupload = CZTOUYU(
        cookies_path, login_url, zhibo_url, watch_room_url, input_directory, only_msg
    )
    try:
        await autoupload.auto_start_zhibo(file_path, habit_name, habit_detail)
    except Exception as mye:
        print(mye)
        traceback.print_exc()
        await autoupload.auto_stop_zhibo()


async def rtmp_timeout_task(input_directory, output_url):
    """_summary_

    Args:
        input_directory (_type_): _description_
        output_url (_type_): _description_
    """
    try:
        # 每天自动直播5小时18000
        timestamp1 = time.time()
        while True:
            await local_file_to_rtmp(input_directory, output_url)
            timestamp2 = time.time()
            time_difference = timestamp2 - timestamp1
            if int(time_difference) > 18000:
                logging.info("timeout")
                break
    except Exception as mye:
        print(mye)
        traceback.print_exc()


async def local_file_to_rtmp(input_directory, output_url):
    """_summary_
    Args:
         # 本地文件夹路径，包含多个视频文件
         # 输出 URL，可以是 RTMP 服务器地址
    """
    print(input_directory)
    random_file_list = []
    timestamp1 = time.time()
    for root, _, files in os.walk(input_directory):
        for file in files:
            # 拼接路径
            file_path = os.path.join(root, file)
            if file_path.endswith(".mp4") or file_path.endswith(".flv"):
                random_file_list.append(file_path)
    print(random_file_list)
    if len(random_file_list) == 0:
        print("empty dir")
        return
    # 随机排序文件列表
    random.shuffle(random_file_list)
    print(random_file_list)

    # 遍历文件列表并推流
    for file_name in random_file_list:
        # 构建完整的文件路径
        if file_name.endswith(".mp4") or file_name.endswith(".flv"):
            print(file_name)
            await start_live_stream(file_name, output_url)
            timestamp2 = time.time()
            time_difference = timestamp2 - timestamp1
            # 没错播放不超过3小时
            if int(time_difference) > 14400:
                break


async def start_live_stream(input_file, rtmp_url):
    """Stream video file to RTMP server using FFmpeg"""
    sys.stdout.reconfigure(encoding="utf-8")
    ffmpeg_cmd = f'ffmpeg -re -i {input_file} -c:v libx264 -preset veryfast -maxrate 2M -bufsize 4M -pix_fmt yuv420p -c:a aac -b:a 128k  -f flv -y "{rtmp_url}"'
    print(ffmpeg_cmd)

    # Create subprocess
    process = await asyncio.create_subprocess_shell(
        ffmpeg_cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
    )

    # Wait for completion and get output
    stdout, stderr = await process.communicate()

    if process.returncode == 0:
        print("Subprogram success")
    else:
        print("Subprogram failed")
        print(stderr.decode())  # Decode the bytes to string


def start_live_stream1(input_file, rtmp_url):
    """_summary_

    Args:
        input_file (_type_): _description_
        output_url (_type_): _description_
    """
    sys.stdout.reconfigure(encoding="utf-8")
    # 构建 FFmpeg 命令行，这里使用 -re 表示以实时速率读取输入文件
    ffmpeg_cmd = (
        f'ffmpeg -re -i {input_file} -vcodec copy -acodec copy  -f flv -y "{rtmp_url}"'
    )
    print(ffmpeg_cmd)
    logging.info(ffmpeg_cmd)

    result = subprocess.run(
        ffmpeg_cmd,
        shell=True,
        capture_output=True,
        text=True,
        check=False,
        encoding="utf-8",
        timeout=10800,
    )

    # 获取命令执行结果
    output = result.stdout
    error = result.stderr
    # 打印输出结果
    print(output)
    # 打印错误结果
    print(error)


async def start_server():
    if platform.system() == "Windows":
        LOG_PATH = r"D:\mp4\log\douyu.log"
        MP4_DIR = r"D:\mp4\speak"
    if platform.system() == "Darwin":
        LOG_PATH = r"/Users/wangchuanyi/mp4/log/bibi.log"
        MP4_DIR = r"/Users/wangchuanyi/mp4/zhibo"
    else:
        MP4_DIR = r"D:\mp4\speak"
        LOG_PATH = "douyu.log"
    logging.basicConfig(
        level=logging.DEBUG, format=LOG_FORMAT, datefmt=DATE_FORMAT, filename=LOG_PATH
    )

    job_defaults = {"coalesce": False, "max_instances": 1}

    await interface_auo_start_douyu_zhibo(MP4_DIR, 2)
    backsched = BlockingScheduler(job_defaults=job_defaults, timezone="Asia/Shanghai")

    backsched.add_job(
        lambda: asyncio.run(interface_auo_start_douyu_zhibo(MP4_DIR, 2)),
        CronTrigger.from_crontab("30 11 * * *"),
        args=[],
        id="get_up",
    )
    backsched.start()
    # playwright codegen https://www.douyu.com/creator/main/live


asyncio.run(start_server())
